package com.topscomm.gpm.utils;

import com.topscomm.pub.util.ConvertUtil;
import com.topscomm.gpm.GpmSystemConst;
import com.topscomm.gpm.pojo.GpmProjectTeamEntity;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import org.apache.xmlbeans.XmlCursor;
import org.springframework.util.CollectionUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description TODO
 * @Classname GenerateAppointmentTemplateUtil
 * @Date 2021/12/14
 * @Created by jiangtao
 */
public class GenerateAppointmentTemplateUtil extends GenerateWordTemplateUtil{
	private static final List<String> specialSymbol = new ArrayList<>();
	static {
		for (int i = 0; i < 10; i++) {
			specialSymbol.add(ConvertUtil.convertToString(i));
		}
	}


	/**
	 * 替换word文档中的文本
	 *
	 * @param paraMap
	 * @throws Exception
	 */
	public static void readWordFile(Map<String, Object> paraMap, String sourcefilePath, String destFilePath, String fileName) throws Exception {
		        System.out.println("!!!!!!!!!"+ XWPFDocument.class.getProtectionDomain().getCodeSource().getLocation());
		File demoFile = new File(sourcefilePath);
		FileInputStream in = new FileInputStream(demoFile);
		XWPFDocument xwpf = new XWPFDocument(in);

		insertParam(paraMap);
		dealParam(paraMap);
		// 替换文本中的占位符
		changeParagraphText(xwpf, paraMap);

		// 替换第一个表格
		changeTableText(xwpf, (List<Map<String, Object>>) paraMap.get("headlist"), xwpf.getTables().get(0), false);
		changeTableText(xwpf, (List<Map<String, Object>>) paraMap.get("sslist"), xwpf.getTables().get(1), false);
		replaceTable(xwpf.getTables().get(3), paraMap);

		// 循环生成剩余的表格
		changeTableText(xwpf, paraMap, xwpf.getTables().get(2));


		OutputStream os = new FileOutputStream(destFilePath + "/" + fileName + ".docx");
		xwpf.write(os);
		closeStream(in);
		closeStream(os);
	}

	private static void insertParam(Map<String, Object> paraMap) {
		if (null == paraMap || paraMap.isEmpty()) {
			return;
		}
		List<Map<String, Object>> headList = new ArrayList<>();
		Map<String, Object> map1 = new HashMap<>();
		map1.put("appointmentnumber", paraMap.get("appointmentnumber"));
		map1.put("signercode", paraMap.get("signercode"));
		headList.add(map1);
		paraMap.put("headlist", headList);
		List<Map<String, Object>> footlist = new ArrayList<>();
		Map<String, Object> map2 = new HashMap<>();
		map2.put("nowdateup", paraMap.get("nowdateup"));
		footlist.add(map2);
		paraMap.put("footlist", footlist);

		// 处理项目组中重复人员
		List<Map<String, Object>> tableList = (List<Map<String, Object>>) paraMap.get("tablelist");
		if (CollectionUtils.isEmpty(tableList)) {
			return;
		}
		listSortBySortCode(tableList);
		for (Map<String, Object> map : tableList) {
			List<Map<String, Object>> list = (List<Map<String, Object>>) map.get("table");
			if (CollectionUtils.isEmpty(list)) {
				continue;
			}
			listSortByPosition(list);
			// 获取该组撤销人员工号
			Set<String> userCodeSet = list.stream().filter(item -> GpmSystemConst.Sd_TAEM_APPOINTMENTTYPE_REVOKE.equals(ConvertUtil.convertToString(item.get(GpmProjectTeamEntity.FieldAppointmenttype))))
					.map(item -> ConvertUtil.convertToString(item.get(GpmProjectTeamEntity.FieldUsercode))).collect(Collectors.toSet());
			if (CollectionUtils.isEmpty(userCodeSet)) {
				// 该组没有任命人员不需要处理
				continue;
			}
			// 过滤掉同一组中既有任命又有撤销的人员 （同一人员既有撤销又有任命）
			list = list.stream().filter(item -> !userCodeSet.contains(ConvertUtil.convertToString(item.get(GpmProjectTeamEntity.FieldUsercode)))).collect(Collectors.toList());
			map.put("table", list);
		}
	}
	public static void listSortBySortCode(List<Map<String, Object>> list) {
		if (org.apache.commons.collections.CollectionUtils.isNotEmpty(list)) {
			Collections.sort(list, new Comparator<Map<String, Object>>() {
				@Override
				public int compare(Map<String, Object> o1, Map<String, Object> o2) {
					int sortCodeO1 = ConvertUtil.convertToInt(o1.get("sortcode"));
					int sortCodeO2 = ConvertUtil.convertToInt(o2.get("sortcode"));
					if (sortCodeO1 > sortCodeO2) {
						return 1;
					}
					else if (sortCodeO1 < sortCodeO2) {
						return -1;
					}
					else {
						Date createOn1 = ConvertUtil.convertToDate(o1.get("createon"));
						Date createOn2 = ConvertUtil.convertToDate(o2.get("createon"));
						if (createOn1.before(createOn2)) {
							return -1;
						}
						if (createOn2.before(createOn1)) {
							return 1;
						}
						return 0;
					}
				}
			});
		}
	}

	/**
	 * @Description:    根据职位排序
	 * @Author:         mengmeng
	 * @Date:           2021/9/11 9:38
	 * @Version:        1.0
	 */
	public static void listSortByPosition(List<Map<String, Object>> list) {
		if (org.apache.commons.collections.CollectionUtils.isNotEmpty(list)) {
			Collections.sort(list, new Comparator<Map<String, Object>>() {
				@Override
				public int compare(Map<String, Object> o1, Map<String, Object> o2) {
					String role1 = ConvertUtil.convertToString(o1.get(GpmProjectTeamEntity.FieldProjectrole));
					String role2 = ConvertUtil.convertToString(o2.get(GpmProjectTeamEntity.FieldProjectrole));
					int sort1 = ConvertUtil.convertToInt(o2.get(GpmProjectTeamEntity.FieldSortcode));
					int sort2 = ConvertUtil.convertToInt(o2.get(GpmProjectTeamEntity.FieldSortcode));
					if (GpmSystemConst.Sd_TEAM_PROJECT_ROLE_LEADER.equals(role1)) {
						if (GpmSystemConst.Sd_TEAM_PROJECT_ROLE_LEADER.equals(role2)) {
							// 如果都是组长，则按照排序吗升序排序
							return sort1 - sort2;
						}
						// 如果role2不是组长，role1是组长，则role1放在前面
						return -1;
					}
					else {
						if (GpmSystemConst.Sd_TEAM_PROJECT_ROLE_LEADER.equals(role2)) {
							// 如果role2是组长，role1不是组长，则role2放在前面
							return 1;
						}
						// 如果都不是组长，则按排序吗升序排序
						return sort1 - sort2;
					}
				}
			});
		}
	}

	private static void dealParam(Map<String, Object> paraMap) {
		if (null == paraMap || paraMap.isEmpty()) {
			return;
		}
		for (Map.Entry<String, Object> entry : paraMap.entrySet()) {
			Object value = entry.getValue();
			if (value instanceof String) {
				paraMap.put(entry.getKey(), fillStr(String.valueOf(value), entry.getKey()));
			}
			if (value instanceof List) {
				List<Map<String, Object>> list = (List<Map<String, Object>>) value;
				for (Map<String, Object> map : list) {
					dealParam(map);
				}
			}
		}
	}

	private static boolean notChinese(String str) {
		int length = str.length();
		int byteLength = str.getBytes().length;
		return length == byteLength;
	}

	private static String fillStr(String str, String key) {
		if ("appointmentnumber".equals(key) && str.contains("[") && str.contains("]")) {
			return str.replace("[", "【").replace("]", "】");
		}
		// 两个字的名字中间增加空格
		if (("username".equals(key) || "ss".equals(key)) && str.length() == 3 && specialSymbol.contains(str.substring(2))) {
			str = str.substring(0, 2);
			return  str.charAt(0) + "  " + str.substring(1);
		}
		if (("username".equals(key) || "ss".equals(key)) && str.length() == 4 && specialSymbol.contains(str.substring(3))) {
			str = str.substring(0, 3);
		}
		if (("username".equals(key) || "ss".equals(key)) && str.length() == 5 && specialSymbol.contains(str.substring(4))) {
			str = str.substring(0, 4);
		}
		if (notChinese(str)) {
			return str;
		}
		if (str.length() != 2) {
			return str;
		}
		return str.charAt(0) + "  " + str.charAt(1);
	}

	/**
	 * @Description:    替换表格中的内容，该方法会删除掉文档中原来的表格，根据原文档中表格中的占位符，使用list列表中的数据替换，生成表格的行数会根据list的size决定
	 * @Author:         mengmeng
	 *                  withHead: true表示新生成的表格有表头， false表示没有表头
	 * @Date:           2021/8/11 9:25
	 * @Version:        1.0
	 */
	public static void changeTableText(XWPFDocument document, Map<String, Object> textMap, XWPFTable table) {
		// 获取当前表格前面的paragraph
		int posOfTable = document.getPosOfTable(table);
		XWPFParagraph paragraphArray = document.getParagraphArray(posOfTable);


		List<Map<String, Object>> tableList = (List<Map<String, Object>>) textMap.get("tablelist");
		for (Map<String, Object> map : tableList) {
			List<Map<String, Object>> mapList = (List<Map<String, Object>>) map.get("table");
			// 如果组员是空的，项目组也不展示
			if (CollectionUtils.isEmpty(mapList)) {
				continue;
			}
			// 在当前paragraph获得节点，创建一个新的table
			XmlCursor cursor = paragraphArray.getCTP().newCursor();
			XWPFTable newCreateTable = document.insertNewTbl(cursor);
			newCreateTable.getCTTbl().setTblPr(table.getCTTbl().getTblPr());

			// 表格标题行
			XWPFTableRow newCreateRow = newCreateTable.createRow();
			CopyTableRow(newCreateRow, table.getRow(0));// 复制行
			replaceTableRow(newCreateRow, map);
			// 循环生成表格内容行
			for (Map<String, Object> map1 : mapList) {
				XWPFTableRow newCreateRow1 = newCreateTable.createRow();
				CopyTableRow(newCreateRow1, table.getRow(1));// 复制模板行
				replaceTableRow(newCreateRow1, map1);// 处理标签替换
			}
			newCreateTable.removeRow(0);// 移除多出来的第一行
			document.insertNewParagraph( paragraphArray.getCTP().newCursor());
		}


		document.removeBodyElement(posOfTable);
		document.removeBodyElement(posOfTable);
		document.removeBodyElement(posOfTable);
		document.createParagraph();// 添加回车换行
	}
	public static void changeTableText1(XWPFDocument document, List<Map<String, Object>> list, XWPFTable table, boolean withHead) {
		int posOfTable = document.getPosOfTable(table);
		// 获取当前表格前面的paragraph
		XWPFParagraph paragraphArray = document.getLastParagraph();

		// 在当前paragraph获得节点，创建一个新的table
		XmlCursor cursor = paragraphArray.getCTP().newCursor();
		XWPFTable newCreateTable = document.insertNewTbl(cursor);
		newCreateTable.getCTTbl().setTblPr(table.getCTTbl().getTblPr());

		if (withHead) {
			// 复制表头
			XWPFTableRow newCreateRow = newCreateTable.createRow();
			CopyTableRow(newCreateRow, table.getRow(0));// 复制行
		}

		for (int i = 0; i < list.size(); i++) {
			XWPFTableRow newCreateRow1 = newCreateTable.createRow();
			CopyTableRow(newCreateRow1, table.getRow(withHead ? 1 : 0));// 复制模板行
			replaceTableRow(newCreateRow1, list.get(i));// 处理标签替换
		}

		document.removeBodyElement(posOfTable);
		newCreateTable.removeRow(0);// 移除多出来的第一行
		document.createParagraph();// 添加回车换行
	}
}
